package com.bnq.logc

import com.bnq.logc.action.SendAction
import com.bnq.logc.action.WriteAction
import com.bnq.logc.data.CheckUploadResult
import com.bnq.logc.manager.ExecutorManager
import com.bnq.logc.printer.DefaultSendPrinter
import com.bnq.logc.printer.DelayLogcPrinter
import com.bnq.logc.printer.IOLogcPrinter
import com.bnq.logc.printer.LogcPrinter
import com.bnq.logc.printer.MmapLogcPrinter
import com.bnq.logc.printer.SendPrinter
import com.bnq.logc.task.*
import com.bnq.logc.upload.UploadFileManager
import com.bnq.logc.utils.FileUtil
import java.io.File
import java.util.concurrent.TimeUnit

class LogcDispatcher() {

    private val printers = mutableListOf<LogcPrinter>(
        DelayLogcPrinter { IOLogcPrinter(LogcManager.getConfig().getLocalFileDir().absolutePath) },
        DelayLogcPrinter { MmapLogcPrinter(LogcManager.getConfig().getLocalFileDir().absolutePath) }
    )

    private val sendPrinters = mutableListOf<SendPrinter>(
        DefaultSendPrinter(LogcManager.getConfig().mSendUrl)
    )

    fun dispatchAction(action: WriteAction){
        val task = WriteLogTask(action,this)
        if(action.isMainThread){
            postMainTask(task)
        }else{
            postIOTask(task)
        }
    }

    @Synchronized
    fun dispatchPrinter(message:String){
        printers.forEach { printer->
            if(printer.isEnabled()){
                printer.print(message)
            }
        }
    }

    @Synchronized
    fun dispatchSendPrinter(map: Map<String,Any?>){
        sendPrinters.forEach { printer->
            if(printer.isEnabled()){
                printer.send(map)
            }
        }
    }

    private fun postIOTask(task: LogTask){
        ExecutorManager.ioExecutor.execute(task)
    }

    private fun postMainTask(task: LogTask){
        ExecutorManager.mainExecutor.execute(task)
    }

    fun dispatchUpload(action: WriteAction) {
        if(LogcManager.getConfig().mIsUploadLog){
            ExecutorManager.scheduleExecutor.schedule({
                UploadFileManager.checkAndUploadFileLast1()
            },3,TimeUnit.SECONDS)
        }
    }

    fun dispatchUploadOne() {
        if(LogcManager.getConfig().mIsUploadLog){
            ExecutorManager.scheduleExecutor.schedule({
                UploadFileManager.checkAndUploadFileLast1()
            },3,TimeUnit.SECONDS)
        }
    }

    fun dispatchUploadCountNow(count:Int,callback:((CheckUploadResult)->Unit)? = null){
        if(LogcManager.getConfig().mIsUploadLog){
            ExecutorManager.scheduleExecutor.schedule({
                UploadFileManager.checkAndUploadFileLastCount(count,callback)
            },1,TimeUnit.SECONDS)
        }
    }

    /**
     * 上传原始文件，远程服务器存放的路径固定，都存在logc/log/YYYY-MM/YYYY-MM-DD/{UniqueCode}路径下
     */
    fun dispatchFileNow(files:List<File>, callback:((CheckUploadResult)->Unit)? = null){
        ExecutorManager.scheduleExecutor.schedule({
            UploadFileManager.checkAndUploadFiles(files,callback)
        },1,TimeUnit.SECONDS)
    }

    /**
     * 上传文件，可以指定远程服务器存放的路径，如果不指定则存在logc/tmp/路径下
     */
    fun dispatchTmpFileNow(files:List<File>, cloudPathNames:List<String>, callback:((CheckUploadResult)->Unit)? = null){
        ExecutorManager.scheduleExecutor.schedule({
            UploadFileManager.checkAndUploadTmpFile(files,cloudPathNames,callback)
        },1,TimeUnit.SECONDS)
    }

    fun dispatchSend(action: SendAction) {
        if(LogcManager.getConfig().mIsSendLog){
            val sendAction = SendLogTask(action,this)
            ExecutorManager.netExecutor.execute(sendAction)
        }
    }

    fun dispatchDelete(){
        val deleteAction = DeleteLogTask()
        ExecutorManager.scheduleExecutor.execute(deleteAction)
    }

    fun dispatchUploadSimpleCacheLog(){
        if(LogcManager.getConfig().mIsOpenSimpleCacheLogUpload){
            val parentDir =
                LogcManager.getConfig().getLocalSimpleCacheLogPathParentDir()
            if(parentDir.exists()){
                val needUploadFiles = FileUtil.findFiles(parentDir){it.name.endsWith(".log")}
                if(needUploadFiles.isNotEmpty()){
                    val task = UploadTmpFileTask(needUploadFiles)
                    ExecutorManager.scheduleExecutor.execute(task)
                }
            }
        }
    }

}